﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
using System.ComponentModel;
using System.Windows.Markup;

namespace Vision.Core.ActivityComponents.Conversion
{
    [ContentProperty("Body")]
    [Designer(typeof(FromToDesigner))]
    public sealed class FromTo<TKey,TValue> : NativeActivity
    {
        /// <summary>
        /// 
        /// </summary>
        [Category("Input")]
        [RequiredArgument]
        public InArgument<TKey> Source { get; set; }
        
        /// <summary>
        /// 
        /// </summary>
        [Category("Output")]
        public OutArgument<TValue> Output { get; set; }

        /// <summary>
        /// 
        /// </summary>
        [Browsable(false)]
        public ActivityAction<TValue> Body { get; set; }

        public FromTo()
        {
            this.Body = new ActivityAction<TValue>()
            {
                Argument = new DelegateInArgument<TValue>()
                {
                    Name = typeof(TValue).Name.ToLower() + "Argument"
                }
            };
        }

        protected override void Execute(NativeActivityContext context)
        {
            if (typeof(TKey) == typeof(string))
            {
                convertFromString(context);
            }
            else if (typeof(TKey) == typeof(System.Xml.XmlReader))
            {
                convertFromXmlReader(context);
            }
			else if (typeof(TKey) == typeof(byte[]))
			{
				convertFromByteArray(context);
			}
			else if (typeof(TKey) == typeof(DateTime))
			{
				convertFromDateTime(context);
			}
			else
				throw new InvalidCastException(String.Format("Unable to convert from type {0}.", typeof(TKey).Name));

            if (this.Body != null && this.Body.Handler != null)
                context.ScheduleAction<TValue>(this.Body, Output.Get(context));
        }

		#region Conversions
		private void convertFromDateTime(NativeActivityContext context)
		{
			// CONVERT DateTime -------------------

			// TO string
			if (typeof(TValue) == typeof(int))
			{
				this.Output.Set(context, this.Source.Get<DateTime>(context).ToString());
			}
			// TO byte[]
			else if (typeof(TValue) == typeof(byte[]))
			{
				System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
				this.Output.Set(context, encoding.GetBytes(this.Source.Get<DateTime>(context).ToString()));
			}
			else
				throw new InvalidCastException(string.Format("DateTime type can not be converted to type {0}.", typeof(TValue).Name));
		}

        private void convertFromString(NativeActivityContext context)
        {
            // CONVERT string -------------------
            
            // TO int
            if (typeof(TValue) == typeof(int))
            {
                this.Output.Set(context, int.Parse(this.Source.Get<string>(context)));
            }
            // TO long
            else if (typeof(TValue) == typeof(long))
            {
                this.Output.Set(context, long.Parse(this.Source.Get<string>(context)));
            }
            // TO float
            else if (typeof(TValue) == typeof(float))
            {
                this.Output.Set(context, float.Parse(this.Source.Get<string>(context)));
            }
            // TO decimal
            else if (typeof(TValue) == typeof(decimal))
            {
                this.Output.Set(context, decimal.Parse(this.Source.Get<string>(context)));
            }
            // TO DateTime
            else if (typeof(TValue) == typeof(DateTime))
            {
                this.Output.Set(context, DateTime.Parse(this.Source.Get<string>(context)));
            }
            // TO char[]
            else if (typeof(TValue) == typeof(char[]))
            {
                this.Output.Set(context, this.Source.Get<string>(context).ToCharArray());
            }
            // TO byte[]
            else if (typeof(TValue) == typeof(byte[]))
            {
                System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
                this.Output.Set(context, encoding.GetBytes(this.Source.Get<string>(context)));
            }
            else
                throw new InvalidCastException(string.Format("String type can not be converted to type {0}.", typeof(TValue).Name));
        }

		private void convertFromByteArray(NativeActivityContext context)
		{
			// CONVERT byte[] -------------------

			// TO string
			if (typeof(TValue) == typeof(string))
			{
				System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
				this.Output.Set(context, encoding.GetString(this.Source.Get<byte[]>(context)));
			}
			// TO DateTime
			else if (typeof(TValue) == typeof(DateTime))
			{
				System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
				string sDateTime = encoding.GetString(this.Source.Get<byte[]>(context));
				this.Output.Set(context, DateTime.Parse(sDateTime));
			}
			else
				throw new InvalidCastException(string.Format("Byte[] type can not be converted to type {0}.", typeof(TValue).Name));
		}

        private void convertFromXmlReader(NativeActivityContext context)
        {
            // CONVERT XmlReader -------------------

            // TO string
            if (typeof(TValue) == typeof(string))
            {
                System.Xml.XmlReader reader = this.Source.Get<System.Xml.XmlReader>(context);
                this.Output.Set(context, System.Xml.Linq.XDocument.Load(reader).ToString(System.Xml.Linq.SaveOptions.DisableFormatting));
                //this.Output.Set(context, long.Parse(this.Source.Get<string>(context)));
            }
            // TO byte[]
            if (typeof(TValue) == typeof(byte[]))
            {
                System.Xml.XmlReader reader = this.Source.Get<System.Xml.XmlReader>(context);
                string output = System.Xml.Linq.XDocument.Load(reader).ToString(System.Xml.Linq.SaveOptions.DisableFormatting);
                
                System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
                this.Output.Set(context, encoding.GetBytes(output));
            }
            // TO System.Xml.Linq.XDocument
            else if (typeof(TValue) == typeof(System.Xml.Linq.XDocument))
            {
                System.Xml.XmlReader reader = this.Source.Get<System.Xml.XmlReader>(context);
                this.Output.Set(context, System.Xml.Linq.XDocument.Load(reader));
            }
            // TO 
            else if (typeof(TValue) == typeof(System.Xml.XmlDocument))
            {
                System.Xml.XmlReader reader = this.Source.Get<System.Xml.XmlReader>(context);
                System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
                xmlDoc.Load(reader);
                this.Output.Set(context, xmlDoc);
            }
        }
        #endregion
    }
}
